package com.boatAnchorAssistant.service.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boatAnchorAssistant.pojo.dto.role.UserRoleDto;
import com.boatAnchorAssistant.pojo.dto.userDataDictionary.UserDataDictionaryDto;
import com.boatAnchorAssistant.pojo.dto.userRoleMp.SelectUserRoleMpDto;
import com.boatAnchorAssistant.pojo.dto.userRoleMp.UserUnbindRoleDto;
import com.boatAnchorAssistant.pojo.entity.*;
import com.boatAnchorAssistant.pojo.event.user.CreateUserEvent;
import com.boatAnchorAssistant.pojo.event.user.EditUserEvent;
import com.boatAnchorAssistant.pojo.param.user.*;
import com.boatAnchorAssistant.pojo.vo.user.*;
import com.boatAnchorAssistant.pojo.dto.user.*;
import com.boatAnchorAssistant.service.config.FixedValueConfig;
import com.boatAnchorAssistant.service.repository.in.*;
import com.boatAnchorAssistant.service.service.in.UserService;
import com.boatAnchorAssistant.service.utils.PasswordUtil;
import com.boatAnchorAssistant.service.utils.StringUtil;
import nirvana.core.context.WebContext;
import nirvana.core.domains.vo.PageResult;
import nirvana.core.exceptions.BizException;
import nirvana.core.utils.ids.IdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 【描 述】：用户服务
 * 【环 境】：J2SE 17
 * 【详 细】：
 *
 */
@Service
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;

    private final RoleRepository roleRepository;

    private final UserRoleMpRepository userRoleMpRepository;

    private final UserDataDictionaryRepository userDataDictionaryRepository;

    private final ResourceRepository resourceRepository;

    private final AuthorizationRepository authorizationRepository;

    private final DepartmentRepository departmentRepository;

    private final ExpandValueRepository expandValueRepository;

    private final ApplicationEventPublisher publisher;
    private final DataDictionaryRepository dataDictionaryRepository;

    public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository, UserRoleMpRepository userRoleMpRepository, UserDataDictionaryRepository userDataDictionaryRepository, ResourceRepository resourceRepository, AuthorizationRepository authorizationRepository, DepartmentRepository departmentRepository, ExpandValueRepository expandValueRepository, ApplicationEventPublisher publisher, DataDictionaryRepository dataDictionaryRepository) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.userRoleMpRepository = userRoleMpRepository;
        this.userDataDictionaryRepository = userDataDictionaryRepository;
        this.resourceRepository = resourceRepository;
        this.authorizationRepository = authorizationRepository;
        this.departmentRepository = departmentRepository;
        this.expandValueRepository = expandValueRepository;
        this.publisher = publisher;
        this.dataDictionaryRepository = dataDictionaryRepository;
    }


    /**
     * 创建用户
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createUser(CreateUserParam param) {
        User user = new User();
        BeanUtils.copyProperties(param, user);
        Long id = IdGenerator.SNOW.generate();
        user.setId(id);

        //设置密码
        String password = "qwer1234";
        password = PasswordUtil.passwordBcryptEncode(id.toString(), password);
        user.setPassword(password);

        Long departmentId = param.getDepartmentId();
        Department department = departmentRepository.getByIdCheck(departmentId);
        user.setTenantId(department.getTenantId());


        userRepository.create(user);

        List<Long> roleIdList = param.getRoleIdList();

        if (roleIdList != null) {

            List<UserRoleMp> mpList = new ArrayList<>();
            roleIdList = roleIdList.stream()
                    .distinct()
                    .collect(Collectors.toList());
            for (Long roleId : roleIdList) {
                UserRoleMp mp = new UserRoleMp();
                mp.setUserId(id);
                mp.setRoleId(roleId);
                mp.setId(IdGenerator.SNOW.generate());
                mpList.add(mp);
            }
            userRoleMpRepository.saveBatch(mpList);
        }

        createUserDataDictionary(id, param.getAreaIdList());

        //保存拓展字段
        Map<String, String> expandData = param.getExpandData();
        CreateUserEvent event = new CreateUserEvent();
        event.setExpandData(expandData);
        event.setModel("user");
        event.setRecordId(id);
        publisher.publishEvent(event);
    }

    /**
     * 获取用户关联的数据字典
     * @param userId
     * @return
     */
    List<UserDataDictionary> getUserDataDictionaryList(Long userId){
        UserDataDictionary userDataDictionary = new UserDataDictionary();
        userDataDictionary.setUserId(userId);
        userDataDictionary.setIsDelete(false);
        return userDataDictionaryRepository.getListByEntity(userDataDictionary);
    }

    /**
     * 绑定数据字典
     * @param userId
     * @param dataDictionaryIds
     */
    void createUserDataDictionary(Long userId,List<Long> dataDictionaryIds){
        List<UserDataDictionary> listByEntity = getUserDataDictionaryList(userId);
        if (CollectionUtil.isNotEmpty(listByEntity)){
            userDataDictionaryRepository.removeByIds(listByEntity.stream().map(UserDataDictionary::getId).collect(Collectors.toList()));
        }

        if (CollectionUtil.isNotEmpty(dataDictionaryIds)){
            List<UserDataDictionary> mpList = new ArrayList<>();
            dataDictionaryIds = dataDictionaryIds.stream()
                    .distinct()
                    .collect(Collectors.toList());
            for (Long dataDictionaryId : dataDictionaryIds) {
                UserDataDictionary mp = new UserDataDictionary();
                mp.setUserId(userId);
                mp.setDataDictionaryId(dataDictionaryId);
                mp.setId(IdGenerator.SNOW.generate());
                mp.setType(0);
                mpList.add(mp);
            }
            userDataDictionaryRepository.saveBatch(mpList);
        }
    }

    /**
     * 修改用户
     *
     * @param param
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editUser(EditUserParam param) {
        Long id = param.getId();
        User user = userRepository.getByIdCheck(id);

        if (user.getIsSystem()) {
            throw new BizException("系统用户不可编辑");
        }

        BeanUtils.copyProperties(param, user);

        Long departmentId = param.getDepartmentId();
        Department department = departmentRepository.getByIdCheck(departmentId);
        user.setTenantId(department.getTenantId());


        userRepository.edit(user);

        List<Long> roleIdList = param.getRoleIdList();
        userRoleMpRepository.clean(id);

        if (roleIdList != null) {
            List<UserRoleMp> mpList = new ArrayList<>();
            roleIdList = roleIdList.stream()
                    .distinct()
                    .collect(Collectors.toList());
            for (Long roleId : roleIdList) {
                UserRoleMp mp = new UserRoleMp();
                mp.setUserId(id);
                mp.setRoleId(roleId);
                mp.setId(IdGenerator.SNOW.generate());
                mpList.add(mp);
            }
            userRoleMpRepository.saveBatch(mpList);
        }

        createUserDataDictionary(id, param.getAreaIdList());

        //保存拓展字段
        Map<String, String> expandData = param.getExpandData();
        EditUserEvent event = new EditUserEvent();
        event.setExpandData(expandData);
        event.setModel("user");
        event.setRecordId(id);
        publisher.publishEvent(event);
    }

    /**
     * 编辑用户头像
     * @param param
     */
    @Override
    public void editUserPhoto(EditUserPhotoParam param) {
        User user = userRepository.getByIdCheck(param.getId());
        user.setPhoto(param.getPhoto());
        if (!userRepository.edit(user)) {
            throw new BizException("编辑失败");
        }
    }

    /**
     * 编辑用户身份证
     * @param param
     */
    @Override
    public void editUserIdentityCardParam(UploadIdentityCardParam param) {
        User user = userRepository.getByIdCheck(WebContext.getCurrentUserId());
        BeanUtils.copyProperties(param, user);
        if (!userRepository.edit(user)) {
            throw new BizException("编辑失败");
        }
    }

    /**
     * 移除用户
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeUser(Long id) {
        User user = userRepository.getByIdCheck(id);
        if (user.getIsSystem()) {
            throw new BizException("系统用户不可编辑");
        }
        userRepository.removeById(id);
    }

    /**
     * 启动/禁用用户
     *
     * @param id
     */
    @Override
    public void enabledUser(Long id) {
        User user = userRepository.getByIdCheck(id);
        if (user.getIsSystem()) {
            throw new BizException("系统用户不可编辑");
        }
        user.setIsDisable(!user.getIsDisable());
        userRepository.edit(user);
    }

    /**
     * 获取用户详情
     *
     * @param id
     * @return
     */
    @Override
    public GetUserVo getUser(Long id) {
        User user = userRepository.getByIdCheck(id);
        GetUserVo vo = new GetUserVo();
        BeanUtils.copyProperties(user, vo);
        vo.setEnabled(!user.getIsDisable());

        //部门名称
        Department department = departmentRepository.getById(user.getDepartmentId());
        if (department != null) {
            vo.setDepartmentName(department.getName());
        }

        //获取用户的角色列表
        List<Role> roleList = roleRepository.getRoleListByUserId(id);
        if (CollectionUtil.isNotEmpty(roleList)){
            List<String> roleNameList = roleList.stream().map(Role::getName).collect(Collectors.toList());
            List<Long> roleIdList = roleList.stream().map(Role::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(roleNameList)) {
                roleNameList = List.of("用户");
            }
            vo.setRoleIdList(roleIdList);
            vo.setRoleList(roleNameList);
        }

        //获取区域名称
        List<UserDataDictionary> userDataDictionaryList = getUserDataDictionaryList(id);
        if (CollectionUtil.isNotEmpty(userDataDictionaryList)){
            List<Long> dataDictionaryIds = userDataDictionaryList.stream()
                    .map(UserDataDictionary::getDataDictionaryId)
                    .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(dataDictionaryIds)){
                List<DataDictionary> dataDictionaryList = dataDictionaryRepository.listByIds(dataDictionaryIds);
                if (CollectionUtil.isNotEmpty(dataDictionaryList)){
                    List<String> dataDictionaryNameList = dataDictionaryList.stream().map(DataDictionary::getName).collect(Collectors.toList());
                    vo.setAreaList(dataDictionaryNameList);
                    vo.setAreaIdList(dataDictionaryIds);
                }
            }
        }
        Map<String, String> expandDate = expandValueRepository.getExpandDate(id);
        vo.setExpandData(expandDate);
        return vo;
    }

    /**
     * 获取用户 列表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<GetUserListVo> getUserList(GetUserListParam param) {

        SelectUserDto dto = new SelectUserDto();
        BeanUtils.copyProperties(param, dto);

        Page<GetUserListVo> userPage = userRepository.getUserListByDepartment(dto);
        List<GetUserListVo> list = userPage.getRecords();

        List<Long> userIds = list.stream()
                .map(GetUserListVo::getId)
                .collect(Collectors.toList());

        Map<Long, List<UserRoleDto>> listMap = roleRepository.getRoleListByUserIds(userIds);
        Map<Long, List<UserDataDictionaryDto>> areaMap = userDataDictionaryRepository.getListByUserIds(userIds, FixedValueConfig.AREA_ID);

        for (GetUserListVo vo : list) {
            Long id = vo.getId();
            List<UserRoleDto> roleDtoList = listMap.get(id);
            if (roleDtoList != null) {
                String roleNames = roleDtoList.stream()
                        .map(UserRoleDto::getName)
                        .collect(Collectors.joining(","));
                vo.setRoleName(roleNames);
            }

            //如果是高级权限用户，或者是系统用户，显示全部
            if (vo.getIsSystem() || (vo.getAuthorizedType()!=null && vo.getAuthorizedType()==2)){
                vo.setAreaName("全部");
            }else{
                List<UserDataDictionaryDto> areaDtoList = areaMap.get(id);
                if (areaDtoList != null) {
                    String areaNames = areaDtoList.stream()
                            .map(UserDataDictionaryDto::getName)
                            .collect(Collectors.joining(","));
                    vo.setAreaName(areaNames);
                }
            }
        }

        return new PageResult(list, userPage.getTotal());

    }

    /**
     * 获取当前用户信息
     *
     * @return
     */
    @Override
    public GetCurrentUserVo getCurrentUser() {
        Long userId = WebContext.getCurrentUserId();

        GetCurrentUserVo vo = new GetCurrentUserVo();

        GetUserVo user = getUser(userId);
        BeanUtils.copyProperties(user, vo);

        if (CollectionUtil.isNotEmpty(user.getRoleIdList())){
            //获取用户的按钮tag集合
            List<Long> resourceIds = authorizationRepository.getAvailableResourceByTargetIds(user.getRoleIdList());
            List<String> tagList = resourceRepository.getButtonResourceListByIds(resourceIds)
                    .stream()
                    .map(Resource::getTag)
                    .collect(Collectors.toList());
            vo.setTagList(tagList);
        }
        return vo;
    }

    /**
     * 获取用户下拉列表
     *
     * @param param
     * @return
     */
    @Override
    public List<GetUserDownListVo> getUserDownList(GetUserDownListParam param) {
        User po = new User();
        if (param != null) {
            BeanUtils.copyProperties(param, po);
        }
        List<User> userList = userRepository.getListByEntity(po);

        List<GetUserDownListVo> list = new ArrayList<>();
        for (User user : userList) {
            GetUserDownListVo vo = new GetUserDownListVo();
            BeanUtils.copyProperties(user, vo);

            vo.setEnabled(!user.getIsDisable());
            list.add(vo);
        }
        return list;
    }

    /**
     * 根据角色获取用户
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<GetUserListByRoleVo> getUserListByRole(GetUserListByRoleParam param) {
        Long roleId = param.getRoleId();
        roleRepository.getByIdCheck(roleId);

        SelectUserRoleBindDto dto = new SelectUserRoleBindDto();
        BeanUtils.copyProperties(param, dto);
        Page<GetUserListByRoleVo> page = userRepository.getUserRoleBindList(dto);

        return new PageResult<>(page);
    }

    /**
     * 用户绑定角色
     *
     * @param param
     */
    @Override
    public void userBingRole(UserBingRoleParam param) {
        List<Long> userIds = param.getUserIds();
        Long roleId = param.getRoleId();

        List<User> users = userRepository.getListByIds(userIds);
        if (userIds.size() != users.size()) {
            throw new BizException("用户错误");
        }
        roleRepository.getByIdCheck(roleId);

        //校验是否有用户重复添加角色
        SelectUserRoleMpDto dto = new SelectUserRoleMpDto();
        BeanUtils.copyProperties(param, dto);
        List<UserRoleMp> roleMps = userRoleMpRepository.selectUserRoleMp(dto);
        if (!CollectionUtils.isEmpty(roleMps)) {
            throw new BizException("有用户重复关联");
        }


        ArrayList<UserRoleMp> mps = new ArrayList<>();
        for (Long userId : userIds) {
            UserRoleMp mp = new UserRoleMp();
            mp.setUserId(userId);
            mp.setRoleId(roleId);
            mp.setId(IdGenerator.SNOW.generate());
            mps.add(mp);
        }
        userRoleMpRepository.saveBatch(mps);

    }

    /**
     * 解除绑定角色
     *
     * @param param
     */
    @Override
    public void userUnbindRole(UserBingRoleParam param) {
        List<Long> userIds = param.getUserIds();
        Long roleId = param.getRoleId();

        List<User> users = userRepository.getListByIds(userIds);
        //校验用户id
        if (userIds.size() != users.size()) {
            throw new BizException("用户错误");
        }
        roleRepository.getByIdCheck(roleId);

        //校验是否有用户重复添加角色
        UserUnbindRoleDto dto = new UserUnbindRoleDto();
        BeanUtils.copyProperties(param, dto);
        userRoleMpRepository.userUnbindRole(dto);
    }


    /**
     * 重置当前用户密码
     *
     * @param param
     */
    @Override
    public void resetCurrentUserPassword(ResetCurrentUserPasswordParam param) {
        Long userId = WebContext.getCurrentUserId();
        User user = userRepository.getByIdCheck(userId);

        //设置密码
        String password = param.getPassword();
        String userPassword = user.getPassword();

        if (PasswordUtil.passwordConfirm(StringUtil.jointString(userId.toString(), password), userPassword)) {
            throw new BizException("密码不能相同");
        }

        password = PasswordUtil.passwordBcryptEncode(userId.toString(), password);
        user.setPassword(password);

        userRepository.edit(user);
    }

    /**
     * 编辑用户密码
     *
     * @param param
     */
    @Override
    public void editUserPassword(EditUserPasswordParam param) {
        Long userId = param.getUserId();
        User user = userRepository.getByIdCheck(userId);

        //比对旧密码加密后是否和数据库的一致
        String oldPassword = param.getOldPassword();
        if (!PasswordUtil.passwordConfirm(StringUtil.jointString(userId.toString(), oldPassword), user.getPassword())) {
            throw new BizException("旧密码错误");
        }

        //设置密码
        String password = param.getPassword();
        password = PasswordUtil.passwordBcryptEncode(userId.toString(), password);
        user.setPassword(password);

        userRepository.edit(user);
    }

    /**
     * 创建系统用户
     *
     * @param dto
     * @return
     */
    @Override
    public void createAdminUser(CreateAdminUserDto dto) {
        User user = new User();
        BeanUtils.copyProperties(dto, user);

        Long userId = dto.getAdminUserId();
        user.setId(userId);
        user.setIsSystem(Boolean.TRUE);

        Long departmentId = dto.getDepartmentId();
        user.setDepartmentId(departmentId);

        Long tenantId = dto.getTenantId();
        user.setTenantId(tenantId);


        //设置密码
        String password = user.getPassword();
        password = PasswordUtil.passwordBcryptEncode(userId.toString(), password);
        user.setPassword(password);


        // TODO: 2022-06-27 补充异常
       userRepository.create(user);
    }

    /**
     * 批量删除用户
     *
     * @param idList
     */
    @Override
    public void bathRemoveUser(List<Long> idList) {
        userRepository.bathRemoveUser(idList);
    }

    /**
     * 批量移动用户到其他部门下
     *
     * @param dto
     */
    @Override
    public void bathMoveUser(MoveUserDto dto) {
        userRepository.bathMoveUser(dto);
    }

    @Override
    public String getUserFileName(Integer count) {
        //“职工编号_采集时间_职位_姓名 第几张图”
        GetUserVo user = getUser(WebContext.getCurrentUserId());
        //获取当前时间的时间戳
        Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now());
        String job="";
        if (user.getRoleList()!=null){
            job=user.getRoleList().get(0);
        }
        String fileName = user.getNumber() + "_" + timestamp.getTime() + "_" + job + "_" + user.getName() + "_" + count;
        return fileName;
    }
}



